package monkeyTalk;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;

import com.gorillalogic.monkeytalk.java.api.Application;
import com.gorillalogic.monkeytalk.java.error.MonkeyTalkFailure;

/*
 * Store all the commonly used variables and functions in this class
 */
public class BaseClass implements MonkeyTalk {

  /*
   * 1 = debug; 2 = info; 3 = error
   */
  int logLevel = 1;
  boolean writeLogToFile = false;
  static String logFileName = "";

  /* Variable to hold Ipad's IP address */
  static String ipadIP = "10.96.116.242";
  // static String ipadIP = "";
  /* Variables for testresult and object repository */
  String testRunResult;
  public static Map<String, String> sharedORMAP = new HashMap<String, String>();

  /* Variables to hold the test data from Excel spreasheeet */
  String TD_SubAccount;
  String TD_BusName;
  String TD_PropName;
  String TD_PropNum;
  String TD_StreetName;
  String TD_Locality;
  String TD_Town;
  String TD_Postcode;
  String TD_County;
  String TD_SkyLicenceNo;
  String TD_FilterBy;
  String TD_ForSatFlag;

  /* Variables to hold the runtime data from iPad App */
  String skyReferenceNumberInApp;
  String businessNameInApp;
  String outletStatusInApp;
  String propertyNumberInApp;
  String streetInApp;
  String titleInApp;
  String firstNameInApp;
  String classificationInApp;
  String townInApp;
  String positionInApp;
  String postcodeInApp;
  String forSatFlagInApp;
  String telenphonenoInApp;
  String mobilenoInApp;

  /*
   * 
   * @Rule public ErrorCollector collector = new ErrorCollector();
   * 
   * private boolean fatal;
   * 
   * public BaseClass() { fatal=false; }
   */
  /*
   * public void assertEquals(String msg, Object expected, Object actual) { if(getFatal()) {
   * Assert.assertEquals(msg,expected, actual); } else { collector.checkThat(msg, actual,
   * CoreMatchers.equalTo(expected)); } }
   */
  /*
   * public void assertEquals(Object expected, Object actual) { if(getFatal()) {
   * Assert.assertEquals(expected, actual); } else { collector.checkThat(actual,
   * CoreMatchers.equalTo(expected)); } }
   * 
   * public void setFatal(boolean fatalFlag) { fatal = fatalFlag; }
   * 
   * public boolean getFatal() { return fatal; }
   */


  public void log(String type, String message) {

    if (type.equalsIgnoreCase("error") && logLevel <= 3) {
      System.out.println("\n");
      System.out
          .println("ERROR:********************************************************************************************");
      System.out.println(message);
      System.out
          .println("ERROR:********************************************************************************************");
      System.out.println("\n");
    }


    if (type.equalsIgnoreCase("info") && logLevel <= 2) {
      DateFormat formatter = new SimpleDateFormat("hh:mm:ss.SSS");
      Date log_dt = new Date();
      System.out.println("[" + formatter.format(log_dt) + "]" + " INFO: " + message);
    }


    if (type.equalsIgnoreCase("debug") && logLevel <= 1) {
      DateFormat formatter = new SimpleDateFormat("hh:mm:ss.SSS");
      Date log_dt = new Date();
      System.out.println("[" + formatter.format(log_dt) + "]" + " DEBUG: " + message);
    }

    if (writeLogToFile) {
      DateFormat formatter = new SimpleDateFormat("hh:mm:ss.SSS");
      Date log_dt = new Date();
      String logMsg =
          "[" + formatter.format(log_dt) + "]" + " " + type.toUpperCase() + ": " + message;


      try (PrintWriter out =
          new PrintWriter(new BufferedWriter(new FileWriter("./logs/" + logFileName, true)))) {
        out.println(logMsg);
      } catch (IOException e) {
        System.err.println(e);
      }

      /*
       * try { FileWriter fw = new FileWriter("./logs/" + logFileName, true); // the true will
       * append the // new data fw.write(logMsg + "\n");// appends the string to the file
       * fw.close(); } catch (IOException ioe) { System.err.println("IOException: " +
       * ioe.getMessage()); }
       */



    }


  }

  public boolean performContainsValidation(String inputData, String actualData) {
    inputData = inputData.toLowerCase();
    actualData = actualData.toLowerCase();

    boolean result = true;
    String tempArr[] = inputData.split("%");

    /*
     * for(int d=0; d< tempArr.length; d++) { log("info","Array data = " + tempArr[d]); }
     */

    for (int d = 0; d < tempArr.length; d++) {
      if (tempArr[d].isEmpty()) {
        continue;
      }
      if (!actualData.contains(tempArr[d])) {
        result = false;
      }
    }

    return result;
  }



  public boolean performBeginsWithValidation(String inputData, String actualData) {
    inputData = inputData.toLowerCase();
    actualData = actualData.toLowerCase();

    boolean result = true;
    if (inputData.endsWith("%") && !(inputData.startsWith("%"))) {
      if (!actualData.startsWith(inputData.substring(0, inputData.length() - 1))) {
        result = false;
      }
    }
    return result;
  }

  public boolean isSortedByAlpha(String[] list) {
    for (int a = 0; a < list.length - 1; a++) {
      if (list[a].compareTo(list[a + 1]) > 0) {
        log("error", "List not sorted@ row " + a + "Values compared are[" + list[a] + "]["
            + list[a + 1] + "]");
        return false;
      }
    }
    return true;
  }

  public boolean isSortedByNumAsc(String[] list) {
    for (int i = 0; i < list.length - 1; i++) {
      if (Integer.parseInt(list[i]) > Integer.parseInt(list[i + 1])) {
        log("error", "List not sorted@ row " + i + "Values compared are[" + list[i] + "]["
            + list[i + 1] + "]");
        return false;

      }
    }
    return true;
  }

  public boolean isSortedByNumDesc(String[] list) {
    for (int i = 0; i < list.length - 1; i++) {
      if (Integer.parseInt(list[i]) < Integer.parseInt(list[i + 1])) {
        log("error", "List not sorted@ row " + i + "Values compared are[" + list[i] + "]["
            + list[i + 1] + "]");
        return false;

      }
    }
    return true;
  }

  public boolean isSortedByBigNumAsc(String[] list) {
    for (int i = 0; i < list.length - 1; i++) {
      if ((new BigInteger(list[i]).compareTo(new BigInteger(list[i + 1]))) > 0) {
        log("error", "List not sorted@ row " + i + "Values compared are[" + list[i] + "]["
            + list[i + 1] + "]");
        return false;

      }
    }
    return true;
  }


  public static <T> boolean contains(final List<String> actOutletDetailsBasicSection,
      final String string) {
    for (final String e : actOutletDetailsBasicSection)
      if (e == string || string != null && string.equals(e))
        return true;

    return false;
  }


  public String getValueBetweenStrings(String input, String beginStr, String endStr) {

    int beginIndex = input.indexOf(beginStr) + beginStr.length();
    int endIndex = input.indexOf(endStr);
    // log ("info","Substring begin and end index = {" + beginIndex + "  " + endIndex + "}" );
    return input.substring(beginIndex, endIndex).trim();

  }

  public String getValueAfterString(String input, String beginStr) {

    int beginIndex = input.indexOf(beginStr) + beginStr.length();
    // log ("info","Substring begin index = {" + beginIndex + "}" );
    return input.substring(beginIndex, input.length()).trim();

  }

  public void clearSearchResults(Application app) {
    log("info", "Started clearing all the search fields before iteration");
    app.input(sharedORMAP.get("OFS_Subaccount")).clear();
    app.input(sharedORMAP.get("OFS_BusinessName")).clear();
    app.input(sharedORMAP.get("OFS_PropertyName")).clear();
    app.input(sharedORMAP.get("OFS_PropertyNumber")).clear();
    app.input(sharedORMAP.get("OFS_StreetName")).clear();
    app.input(sharedORMAP.get("OFS_Locality")).clear();
    app.input(sharedORMAP.get("OFS_Town")).clear();
    app.input(sharedORMAP.get("OFS_Postcode")).clear();
    app.input(sharedORMAP.get("OFS_County")).clear();
    app.input(sharedORMAP.get("OFS_SkyLicenceNo")).clear();
    log("info", "Clearing complete!");

  }


  public void waitTillSearchCompletes(Application app) throws InterruptedException {
    log("info", "Waiting til the search completes......");
    Thread.sleep(1000);
    boolean searchCompleted = false;
    while (!searchCompleted) {
      String searchResultString = app.view(sharedORMAP.get("OFS_SearchResultCount")).get();
      if (!searchResultString.toLowerCase().contains("searching.")) {
        searchCompleted = true;
      }
    }
  }

  public boolean isTVAgreement(String agreementType) {
    List<String> tvAgreements = new ArrayList<String>();
    tvAgreements.add("WiFi");
    tvAgreements.add("Sky Wi-fi");
    tvAgreements.add("WiFi Standalone");
    tvAgreements.add("WiFi in Hotel Rooms");

    if (tvAgreements.contains(agreementType)) {
      return false;
    }

    return true;

  }


  public String getDataFromArray(String searchString, String label) {
    // log("info","Searching for {" + label + "} in { " + searchString + "}");
    String[] tempArr = searchString.trim().split(label);
    // log("info" , "Length of array = " + tempArr.length);
    if (tempArr.length > 1) {
      return tempArr[1];
    }

    return "NO MATCH FOUND";

  }

  public Date getDateFromString(String dt) throws ParseException {
    dt = dt.trim().replace(" ", "/");
    Date date = new SimpleDateFormat("yyyy/mm/dd", Locale.ENGLISH).parse(dt);
    log("debug", "Date returned from string =" + date);
    return date;
  }

  public Date getDateFromString(String dt, String format) throws ParseException {

    Date date = new SimpleDateFormat(format, Locale.ENGLISH).parse(dt);
    log("debug", "Date returned from string =" + date);
    return date;
  }


  public String getFormattedTodayDatePlus(int days) throws ParseException {
    String formattedDate = "";
    SimpleDateFormat Fday = new SimpleDateFormat("EEEE");
    SimpleDateFormat Fdate = new SimpleDateFormat("dd");
    SimpleDateFormat Fmonth = new SimpleDateFormat("MMM");
    Calendar cal = Calendar.getInstance();
    cal.add(Calendar.DAY_OF_MONTH, days);
    formattedDate =
        Fday.format(cal.getTime()) + " " + Fdate.format(cal.getTime())
            + getDaySuffix(Fdate.format(cal.getTime())) + " " + Fmonth.format(cal.getTime());
    log("debug", "Formatted Date = " + formattedDate);
    return formattedDate;

  }


  public String getDaySuffix(String day) {
    String[] suffixes =
    // 0 1 2 3 4 5 6 7 8 9
        {"th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th",
            // 10 11 12 13 14 15 16 17 18 19
            "th", "th", "th", "th", "th", "th", "th", "th", "th", "th",
            // 20 21 22 23 24 25 26 27 28 29
            "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th",
            // 30 31
            "th", "st"};
    return suffixes[Integer.parseInt(day)];
  }



  public String createRandomNumber(long len) {
    if (len > 18)
      throw new IllegalStateException("To many digits");
    long tLen = (long) Math.pow(10, len - 1) * 9;

    long number = (long) (Math.random() * tLen) + (long) Math.pow(10, len - 1) * 1;

    String tVal = number + "";
    if (tVal.length() != len) {
      throw new IllegalStateException("The random number '" + tVal + "' is not '" + len
          + "' digits");
    }
    return tVal;
  }


  public String getAttrValueFromHTMLElement(String html, String tag, String attribute) {

    Document doc = Jsoup.parse(html);
    Element htmlElem = doc.select(tag).first();
    return htmlElem.attr(attribute);
  }


  /*
   * Implementation of the MonkeyTalk Interface
   */


  @Override
  public void enter(String objectName, String value, Application app) {

    app.input(sharedORMAP.get(objectName)).enterText(value);

  }


  @Override
  public void clear(String objectName, Application app) {
    app.input(sharedORMAP.get(objectName)).clear();
  }


  @Override
  public void click(String objectName, String objectType, Application app) {

    try {
      if (objectType.equalsIgnoreCase("link")) {
        app.link(sharedORMAP.get(objectName)).touchDown();
      }

      if (objectType.equalsIgnoreCase("button")) {
        app.button(sharedORMAP.get(objectName)).touchDown();
      }

      if (objectType.equalsIgnoreCase("view")) {
        app.view(sharedORMAP.get(objectName)).touchDown();
      }
    } catch (MonkeyTalkFailure ex) {
      log("debug", "Monkeytalk failure exception thrown while clicking:" + ex.getMessage());
    }

  }

  @Override
  public void click(String objectName, String objectType, Application app, int noOfRetry) {

    for (int i = 0; i < noOfRetry; i++) {
      // Give a couple of try to click the link.

      try {
        if (objectType.equalsIgnoreCase("link")) {
          app.link(sharedORMAP.get(objectName)).touchDown();
        }

        if (objectType.equalsIgnoreCase("button")) {
          app.button(sharedORMAP.get(objectName)).touchDown();
        }

        if (objectType.equalsIgnoreCase("view")) {
          app.view(sharedORMAP.get(objectName)).touchDown();
        }
      } catch (MonkeyTalkFailure ex) {
        log("debug", "Monkeytalk failure exception thrown while clicking");
        break;
      }

    }

  }

  @Override
  public void check(String objectName, String value, Application app) {
    if (value.equalsIgnoreCase("off")) {
      app.checkBox(sharedORMAP.get(objectName)).off();
    }

    if (value.equalsIgnoreCase("on")) {
      app.checkBox(sharedORMAP.get(objectName)).on();
    }
  }


  @Override
  public void select(String objectName, String value, Application app) {
    app.itemSelector(sharedORMAP.get(objectName)).select(value);

  }

  public void selectByText(String objectName, String value, Application app) {

    String elemRef = "document.getElementById('" + sharedORMAP.get(objectName) + "')";

    int dropdownLength = Integer.parseInt(runJS(elemRef + ".options.length", app));
    String valueToSelect = "";
    for (int i = 0; i < dropdownLength; i++) {
      if (runJS(elemRef + ".options[" + i + "].text", app).equalsIgnoreCase(value)) {
        valueToSelect = runJS(elemRef + ".options[" + i + "].value", app);
      }
    }
    log("debug", "Value to select in dropdown = " + valueToSelect);
    app.itemSelector(sharedORMAP.get(objectName)).select(valueToSelect);

  }



  @Override
  public String getValue(String objectName, String objectType, String property, Application app) {
    // TODO Auto-generated method stub
    return "someting";
  }

  @Override
  public String getValue(String objectName, String objectType, Application app) {
    if (objectType.trim().equalsIgnoreCase("input")) {
      return app.input(sharedORMAP.get(objectName)).get();
    }

    if (objectType.trim().equalsIgnoreCase("itemselector")) {
      return app.itemSelector(sharedORMAP.get(objectName)).get();
    }

    if (objectType.trim().equalsIgnoreCase("checkbox")) {
      return app.checkBox(sharedORMAP.get(objectName)).get();
    }

    if (objectType.trim().equalsIgnoreCase("view")) {
      return app.view(sharedORMAP.get(objectName)).get();
    }

    return "INVALID_OBJECT_TYPE";
  }


  @Override
  public void enterInPopUp(String objectName, String value, Application app) {

    String rawCommand = "Web * Exec app." + sharedORMAP.get(objectName) + "('" + value + "')";
    log("debug", "Raw command to execute in Popup= {" + rawCommand + "}");
    app.raw(rawCommand);
    log("debug", "Raw command executed.");
  }


  @Override
  public String getJSValue(String objectName, String ObjectType, String retValueType,
      Application app) {
    String rawCommand = "";

    if (retValueType.equalsIgnoreCase("count")) {
      rawCommand =
          "Web * ExecAndReturn myvar document.getElementsBy" + ObjectType + "('"
              + objectName.replace(" ", "\\ ") + "').length";
    }

    else if (retValueType.equalsIgnoreCase("value")) {
      rawCommand =
          "Web * ExecAndReturn myvar document.getElementBy" + ObjectType + "('" + objectName
              + "').value";
    }

    else if (retValueType.equalsIgnoreCase("text")) {
      rawCommand =
          "Web * ExecAndReturn myvar document.getElementBy" + ObjectType + "('" + objectName
              + "').innerText";
    }


    log("debug", "Trying to execute raw js in monkey talk {" + rawCommand + "}");
    return app.raw(rawCommand);
  }


  public String runJS(String jsToExecute, Application app) {
    String rawCommand = "Web * ExecAndReturn myvar " + jsToExecute;
    return app.raw(rawCommand);
  }

  public void waitTillViewLoads(String viewName, int timeoutInSecs, Application app)
      throws InterruptedException {

    boolean dataLoadedInView = false;

    for (int i = 0; i < timeoutInSecs; i++) {
      if (!app.view(viewName).get().isEmpty()) {
        dataLoadedInView = true;
        break;
      }
      Thread.sleep(1000);
    }

    log("info", "Data load status in view{" + viewName + "} within {" + timeoutInSecs + "} secs = "
        + dataLoadedInView);


  }



}
